The select tablename, policyname from pg_policies where qual = 'true' query is the right first sweep, but the bug class just past it is the one that ships. Agents rarely leave a bare USING (true) once they've been told not to - they write a policy that mentions the user but doesn't scope to the row:
-- passes both "RLS enabled" and "there's a policy, it mentions auth"createpolicy"Users can view profiles"onpublic.profilesforselectusing(auth.uid()isnotnull);
qual = 'true' misses this (the expression isn't literally true), a linter is satisfied, and every signed-in user reads every row - emails, stripe_customer_id, the lot. Catching it needs the roles, not just the qual:
Empty result is the baseline you want. I hit exactly this shape in three live apps last week (the "does this email exist" login helper is the recurring offender). Put the same red/green test next to your migration so CI catches it: a runnable minimal demo - npm ci && npm test, red on broken, green on fixed, no Docker - is here: github.com/cekuu35/supabase-rls-le...
Good catch, and thanks for the concrete example. auth.uid() is not null is exactly the policy that satisfies a checklist while scoping nothing, and a qual = 'true' sweep can't see it. Your regex check is a handy second pass; I'd add a quick two-user test as well, where user A tries to select user B's row, because that catches shapes a pattern match won't, such as a join through a membership table that isn't filtered.
For further actions, you may consider blocking this person and/or reporting abuse
We're a place where coders share, stay up-to-date and grow their careers.
The
select tablename, policyname from pg_policies where qual = 'true'query is the right first sweep, but the bug class just past it is the one that ships. Agents rarely leave a bareUSING (true)once they've been told not to - they write a policy that mentions the user but doesn't scope to the row:qual = 'true'misses this (the expression isn't literally true), a linter is satisfied, and every signed-in user reads every row - emails,stripe_customer_id, the lot. Catching it needs the roles, not just the qual:Empty result is the baseline you want. I hit exactly this shape in three live apps last week (the "does this email exist" login helper is the recurring offender). Put the same red/green test next to your migration so CI catches it: a runnable minimal demo -
npm ci && npm test, red onbroken, green onfixed, no Docker - is here: github.com/cekuu35/supabase-rls-le...Good catch, and thanks for the concrete example.
auth.uid() is not nullis exactly the policy that satisfies a checklist while scoping nothing, and aqual = 'true'sweep can't see it. Your regex check is a handy second pass; I'd add a quick two-user test as well, where user A tries to select user B's row, because that catches shapes a pattern match won't, such as a join through a membership table that isn't filtered.