Skip to content

RLS: public.users is anonymously readable and updatable (anon can UPDATE any user row) — worth scoping #35

Description

@dmitrymaranik

Hi, and thanks for ElatoAI. I ran a static RLS analyzer (pgrls) over supabase/migrations and wanted to flag the policies on public.users — applying the migrations to a clean Postgres confirms the anon (unauthenticated) role has broad read and write access:

policy cmd role predicate
Enable read access for all users SELECT public USING (true)
Update user table UPDATE anon USING (true) WITH CHECK (true)

Concretely, with just the project's anon API key (no login):

  • read — every row of public.users is selectable.
  • write — every row of public.users is updatable: an anonymous caller can rewrite any user's row, not only their own.

I suspect part of this is intentional for the device path — esp users can update devices is also anon-scoped, so the ESP32 likely talks to Supabase with the anon key. That's a reasonable pattern, but as written these policies are unscoped (USING (true)), so they apply to all rows for any anonymous caller rather than just the row that belongs to the calling device/user.

Worth scoping each to the owning row — e.g. USING (id = <the identifier the device/session carries>) — and moving anything that doesn't truly need to be public off the anon/public role. (Also, lower priority: no FORCE ROW LEVEL SECURITY on these tables, and the same USING (true) public-read shape on devices / languages / personalities.)

I held off on a PR because the right predicate depends on your device-auth model — happy to send one once you confirm which column ties a users row to its device/session and whether the public read is deliberate.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions