A note on sourcing. This analysis is based on publicly available information, including the Moltbook post-mortem disclosure, security researcher reports, and HackerNews discussion threads from late 2025. Where details are inferred from the technical pattern rather than stated explicitly in public disclosures, we say so. This is a case study, not a primary investigation.
What happened
Moltbook launched in mid-2025 as a Notion alternative aimed at solo knowledge workers. According to public reports, it was built primarily using Bolt.new and Cursor, with Supabase as the backend database and auth layer. Within three months of launch, it had accumulated approximately 47,000 registered users.
In October 2025, a security researcher discovered that Moltbook's Supabase anon key — publicly visible in the client-side JavaScript bundle, as intended — could be used to query the documents, blocks, and profiles tables directly via the Supabase REST API, returning data belonging to arbitrary users. According to available information, no authentication beyond possession of the anon key was required to read any user's documents.
The researcher disclosed the finding to Moltbook privately. Based on the public timeline, the company patched the issue within 18 hours of notification by adding RLS policies to the affected tables. They subsequently published a post-mortem acknowledging the exposure and notified affected users.
The data exposed, based on the company's own disclosure, included: document titles and full content, block-level notes data, user profile information including display names and email addresses, and workspace metadata. Moltbook's post-mortem stated there was no evidence of malicious access prior to the researcher's discovery — though, as they acknowledged, absence of evidence is not evidence of absence when you have no access logging on the affected endpoints.
The root cause: Supabase anon key with no RLS
The Supabase architecture Moltbook used is standard and well-documented. The anon key is designed to be public — it identifies the project, not a privileged user. It is safe to include in client-side code. What makes it safe is Row Level Security: policies attached to each table that restrict what data any given request can read or modify based on the authenticated identity of the caller.
Based on available technical information, Moltbook had RLS enabled on their primary tables — the Supabase dashboard would have shown the green shield indicator. What they did not have was policies that actually restricted access. Based on the pattern of what was exposed (all documents readable by the anon role), the most likely configuration was either no policies on the affected tables, or a permissive USING(true) policy that approved every row for every caller.
The practical effect: their public anon key, combined with the Supabase REST API endpoint visible in network requests from any Moltbook page, gave anyone with a browser and basic API knowledge the ability to read every document in the database. The query was as simple as:
The exploit required no special skills. Anyone who opened DevTools on the Moltbook site, copied the anon key from the request headers, and sent a GET request to https://[project].supabase.co/rest/v1/documents?select=* with that key in an apikey header would have received all documents from all users. This is not a sophisticated attack — it is one curl command.
This is the specific failure mode that Supabase's documentation warns about prominently, that security researchers consistently flag in AI-generated Supabase code, and that appears in some form in the majority of vibe-coded Supabase projects we audit at Launch Ready Code. The AI tools that generate Supabase setup code know to enable RLS. They do not reliably generate the policies that make RLS meaningful.
What an audit would have caught — specific P0 findings
The Moltbook configuration would have produced at minimum three P0 findings in a standard Launch Ready Code audit, plus several P1s. Here is what those findings would have looked like:
The documents table has RLS enabled but zero policies defined. Supabase's REST API accepts requests authenticated with the project's public anon key. Any caller with the anon key can retrieve all rows from this table without further authentication. The anon key is visible in every client request. This is a complete data exposure for all 47,000+ document records.
Fix: Add a SELECT policy restricting reads to auth.uid() = user_id. Add INSERT, UPDATE, and DELETE policies with the same constraint. Test by querying the table as the anon role and confirming zero rows are returned.
The profiles table stores display names, email addresses, and user preferences. It has RLS enabled with no policies. All profile data for every registered user is readable by anyone with the anon key. This constitutes a personal data breach under most applicable privacy regulations.
Fix: Add a SELECT policy: USING(auth.uid() = id). For any fields intended to be publicly visible (e.g., display name for shared documents), create a separate restricted policy rather than exposing the entire row.
The Supabase project has no query-level logging configured beyond default Postgres logs, which are not retained or alerted on. There is no mechanism to determine whether the unauthenticated data access was exploited before the security researcher's disclosure. The company cannot provide users with an accurate statement of whether their data was accessed.
Fix: Enable Supabase's built-in log drain to an external destination (Datadog, Loki, or similar). Set an alert on anomalous query volumes from the anon role. Retain logs for at least 90 days.
Timeline of exposure
Based on available public information and the typical development pattern of an AI-assisted Supabase project, the following timeline is consistent with what Moltbook disclosed:
App goes live with no RLS policies
Based on the post-mortem, RLS was enabled on the tables but no policies were created. This is the state the app shipped in. The data was accessible from day one.
47,000 users add data to the exposed database
Over approximately 90 days, users created documents, took notes, and stored personal information — all of it readable without authentication. No monitoring flagged the issue because there was no monitoring to flag it.
Security researcher finds the exposure
According to public reports, a security researcher discovered the issue through routine reconnaissance — inspecting the network requests of a web app they were using. The anon key was visible in request headers; a direct API call returned all documents. The researcher disclosed privately.
RLS policies added, breach contained
Moltbook added RLS policies to the affected tables within 18 hours of notification. The fix itself was straightforward — a handful of SQL statements. The 90-day exposure existed because nobody checked whether RLS was actually enforcing anything.
Public disclosure and user notification
Moltbook published a post-mortem acknowledging the issue. They noted there was no evidence of malicious access but acknowledged they lacked the logging infrastructure to make that determination with confidence.
Lessons for founders building with AI tools
The Moltbook breach is not unusual. It is representative. In our audits of vibe-coded Supabase apps at Launch Ready Code, missing or broken RLS policies appear in the majority of projects. The specifics vary — sometimes it's no policies at all, sometimes it's USING(true), sometimes it's policies that only cover SELECT but not INSERT or UPDATE — but the underlying pattern is consistent.
The reason is structural. AI code generators are optimized to produce working code quickly. "Working" in this context means the app functions: data is read and written, features behave as described. RLS failures often don't prevent the app from functioning in development, where developers typically use the service role key or access the database directly. The failure only manifests when real users hit the production API — and by then, there's already data at risk.
Enabling RLS is not the same as having working RLS
The dashboard green shield means RLS is on. It tells you nothing about whether your policies are correct. Always verify by querying the database as the anon role and as a specific user, checking that the results match your intended access model.
Test as your users — not as your admin CLI
Most development workflows use the Supabase CLI or service role key, which bypasses RLS. Developers never see the failure mode that real users hit. Build test cases that explicitly impersonate the anon and authenticated roles via SQL.
Lack of monitoring means lack of visibility into exposure duration
Moltbook could not tell users whether their data had been accessed. That is the consequence of having no access logging. Basic Supabase log draining to an external store is a one-hour setup that would have made that question answerable.
The fix was 18 hours — the exposure was 90 days
The asymmetry is the point. Fixing RLS takes minutes. The cost of not checking it before launch compounds every day users add data. The Moltbook fix was trivial; the breach notification, legal exposure, and user trust damage were not.
Security researchers find what your users haven't reported yet
Moltbook was notified by a researcher who happened to be using the app and happened to check. This is not a reliable security process. The alternative is to check yourself — before launch, on every schema change, and after every migration.
The three-step check that would have prevented this
Every Supabase project should pass these three tests before any real user data is stored in it. They take under 30 minutes to run and require no specialized tools:
Step 1: Query the anon role. In the Supabase SQL editor, run SET ROLE anon; SELECT * FROM [your table] LIMIT 10; RESET ROLE; for every table that stores user data. If you get rows back on a non-public table, RLS is not working.
Step 2: Impersonate a user and try to access another user's data. Using SET LOCAL role TO authenticated and a specific user's UUID in the JWT claims, query for rows belonging to a different user. If you get results, your USING clause is not enforcing isolation.
Step 3: Search your client-side code for the service role key. Run a search across your repository for SUPABASE_SERVICE_ROLE_KEY and service_role. If either string appears in a file that is not a server-only module, the key is in your bundle.
These three steps are the minimum. A full audit covers type compatibility between auth.uid() and your user_id columns, write policy coverage for INSERT/UPDATE/DELETE, policy interaction effects when you have multiple policies on the same table, and the monitoring configuration that would let you detect and scope any future exposure.
The RLS deep-dive at /resources/supabase-rls-security.html walks through each failure mode with the exact SQL to check for it.
Know where you stand before a researcher tells you
Our free scan checks RLS policy coverage, service key exposure, secrets in bundles, and 47 other security signals. 60 seconds, no account required.
The broader pattern
Moltbook's breach was caused by a configuration gap that is specific to Supabase, but the category of failure is not. AI coding tools build fast and skip the validation steps that a senior developer would apply by habit. They don't run tests as the anon role because they weren't asked to. They don't add query logging because nobody prompted for it. They ship what works — and "works" is defined by whether the features function, not whether the security model is correct.
The responsibility for closing that gap sits with the founder. The tools that generated the code won't close it for you. Neither will the Supabase dashboard, which shows a green shield regardless of whether your policies are functional. The only thing that closes it is deliberately testing the security model before real users trust you with their data.
47,000 users trusted Moltbook with their notes, their work, and their email addresses. That trust was breached not by a sophisticated attacker but by a missing SQL statement. The statement would have taken four minutes to write and would have protected every one of those records from day one.