All articles

Supabase Realtime: When Anonymous Subscriptions Bypass Your RLS

Supabase Realtime: When Anonymous Subscriptions Bypass Your RLS

Supabase Realtime subscriptions respect RLS — usually. Here are the three configurations where anonymous clients still receive row-level events they shouldn't see.

May 1, 2026VibeWShield Team1 min read

Supabase Realtime broadcasts INSERT/UPDATE/DELETE events from Postgres to subscribed clients. The promise: RLS policies apply to the subscription, so an anonymous client never sees rows it can't read.

In practice, three gotchas bite vibe-coded apps.

1. Publication covers the wrong tables

supabase_realtime is the Postgres publication. By default it publishes everything. If you intended only messages to be realtime, but publication still lists users, every INSERT into users (signup) broadcasts full user rows to anonymous subscribers until RLS kicks in — and for that single event, there's a race.

ALTER PUBLICATION supabase_realtime DROP TABLE users;

2. Payload-level filters don't exist

Realtime filters at the row level, not the column level. If a row matches RLS, the ENTIRE row is sent — including columns the client would have been filtered out of in a normal SELECT.

Store PII in a separate table, join at read time.

3. The "anon key" subscribes successfully even when RLS is off

RLS can be completely disabled on a table and Supabase doesn't tell you. supabase.from("your_table").on("INSERT", handler).subscribe() works fine — because "no policy = no restriction = broadcast everything."

Always enable RLS explicitly:

ALTER TABLE your_table ENABLE ROW LEVEL SECURITY;

VibeWShield's Supabase scanner tests all three conditions automatically on every scan.

Free security scan

Test your app for these vulnerabilities

VibeWShield automatically scans for everything covered in this article and more — 18 security checks in under 3 minutes.

Scan your app free