agentleFS
mateuszinganomateuszingano/supabase-rls-rules/skills/supabase-rls/SKILL.md

supabase-rls

Skill0 starsChanged 26 days agoMITView on GitHub

Write Supabase migrations, RLS policies and grants that do not leak data. Use when creating or changing Supabase tables, policies, grants, views or security definer functions, when handling the service_role key, or when debugging 42501 permission denied, 42P17 infinite recursion, PGRST116, PGRST205, or an update/delete that silently changes nothing.

1 other project uses a version of this.

Adopted by

Most recently taken up by

  • Other versions1 project uses a version of this.

    Word for word · 0

    None found.

    Edited · 0

    None found.

    Wrote their own version · 1

    1. penalverbj/ClaudeSkills★ 0same name

    How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.

  • In this repository2 other files it gives its agents.

The file

We split this skill into the rules it gives an agent

8 rules. About 0 are common, 2 are distinctive, and 6 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈2

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 6

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    Never "fix" a 42501 with grant ...

    line 16
  2. Very specific:

    Write one policy per operation (for select, for insert, for update, for delete) and name the role with to authenticated (or to anon).

    line 20
  3. Very specific:

    No policy protects a column it doesn't mention: an owner policy on user_id won't stop a user from changing is_admin on their own row.

    line 23
  4. Distinctive:

    UPDATE also needs a SELECT policy for the same rows, or it silently affects 0 rows.

    line 24
  5. Very specific:

    Never use using (true) / with check (true) on private data.

    line 25
  6. Very specific:

    Never put the service_role / sb_secret_...

    line 36
  7. Very specific:

    Test policies as the real roles (anon, authenticated as user A and as user B), not in the SQL editor, which bypasses RLS.

    line 47
  8. Distinctive:

    Check what the API roles can reach:

    line 48

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Supabase RLS and grants: rules for writing secure migrations

Apply these whenever you create or change a Supabase table, view, function, policy or grant, or write client code that reads or writes Supabase data.

Every table in an exposed schema

  • Enable RLS in the same migration that creates the table: alter table public.x enable row level security;. A table must never exist without it.
  • RLS on with no policy denies everything. Add the policies the app needs in that same migration.
  • Grant explicitly, per table, only to the role that needs it and only the operations the app uses: grant select on public.x to authenticated; New tables don't get automatic grants for anon/authenticated/service_role (Supabase change of Oct 30, 2026); without a grant the API returns 42501 permission denied for table.
  • Never "fix" a 42501 with grant ... on all tables in schema public to anon, authenticated. It also grants every table with RLS off, making it readable and writable with the public anon key.
  • Grant to anon only for data that signed-out visitors should read, and pair it with a policy that allows exactly that.

Policies

  • Write one policy per operation (for select, for insert, for update, for delete) and name the role with to authenticated (or to anon).
  • Wrap auth.uid() as (select auth.uid()) so Postgres evaluates it once per query, not per row.
  • INSERT policies need with check (they can't have using, and without with check they let no rows in). On UPDATE, write both using (which rows) and with check (what they may become). If with check is missing, Postgres checks the new row against using, which is only safe when using is as strict as what a row may become: with an or (shared or team rows) a row can be handed to another user.
  • No policy protects a column it doesn't mention: an owner policy on user_id won't stop a user from changing is_admin on their own row. For sensitive columns, grant update only on the columns users may change (grant update (body) on public.notes to authenticated;).
  • UPDATE also needs a SELECT policy for the same rows, or it silently affects 0 rows.
  • Never use using (true) / with check (true) on private data. Allow it only for data that is public on purpose, and say so in a comment.
  • A policy must not query the table it protects (that raises 42P17 infinite recursion detected in policy). Put the lookup in a security definer function in a non-exposed schema (e.g. private), with set search_path = '', schema-qualified names, a filter on (select auth.uid()), revoke all ... from public and grant execute only to authenticated.
  • Multi-tenant data: scope rows to the caller's tenant through a membership lookup (the helper above), never through a value the client sends.

Views, functions, other schemas

  • Views run with the owner's privileges by default and skip RLS. Create them with with (security_invoker = true), or don't expose them.
  • security definer functions bypass RLS: keep them out of exposed schemas unless they are meant as an API, and validate the caller inside.
  • A table in a non-public schema needs that schema in the Data API's exposed schemas, grant usage on schema ... to <role>, plus the table grant and RLS.

Keys and clients

  • The anon / publishable key is public by design; RLS is what protects data.
  • Never put the service_role / sb_secret_... key in frontend code, NEXT_PUBLIC_* / VITE_* env vars, or anything shipped to the browser. It bypasses all RLS. Use it only on the server.
  • On the server, create the Supabase client from the user's session (request cookies) so auth.uid() resolves; otherwise queries run as anon.

Errors and what they mean

  • 42501 permission denied for table|schema: missing grant or schema usage (before RLS runs).
  • new row violates row-level security policy: an INSERT/UPDATE failed with check.
  • PGRST116 Cannot coerce the result to a single JSON object with .single() and a row that exists: RLS is hiding it from this caller (or there's no session). Use .maybeSingle() only when 0 rows is a normal answer.
  • An update or delete that returns no error but changes nothing: no matching UPDATE/DELETE (or SELECT) policy. Chain .select() to see the affected rows.
  • PGRST205 Could not find the table ... in the schema cache: wrong name/schema, schema not exposed, or a stale cache (notify pgrst, 'reload schema';).

Prove it

  • Test policies as the real roles (anon, authenticated as user A and as user B), not in the SQL editor, which bypasses RLS.
  • Check what the API roles can reach:
    select c.relname,
           has_table_privilege('anon', c.oid, 'select') as anon_can_read,
           c.relrowsecurity as rls_on
    from pg_class c join pg_namespace n on n.oid = c.relnamespace
    where n.nspname = 'public' and c.relkind = 'r'
    order by 1;
    anon_can_read = true with rls_on = false means the table is public.
  • Gate it in CI: npx airlock-rls fails the build when a table ships without RLS or with an always-true policy.

Guides with tested SQL for each rule: https://shipsealed.com/rls/

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.