Install script grants ALL on net tables to PUBLIC, which project owners cannot revoke

Open
#320 0 comments 1 reaction 0 assignees View on GitHub

Maintainers usually reply within 2 days

Nobody has claimed this yet.

Assessment

Difficulty
4/5
Estimated time
3-5 days
Newbie friendliness
42/100
Issue type
Bug
Clarity
Mostly clear
Activity status
Active
Tech stack
postgresql, sql

Research direction

Start with the GRANT statements in sql/pg_net.sql and sql/pg_net--0.11.0--0.12.0.sql, then inspect the upgrade scripts and the SECURITY INVOKER functions named in the issue. Work out which named roles need access while preserving their ability to enqueue requests; done means install and upgrade grants protect the tables without granting all privileges to PUBLIC.

Written by the indexing model from the issue text.

Description

Summary

The install script grants all privileges on the net tables to PUBLIC:

-- sql/pg_net.sql (and since sql/pg_net--0.11.0--0.12.0.sql)
grant usage on schema net to PUBLIC;
grant all on all sequences in schema net to PUBLIC;
grant all on all tables in schema net to PUBLIC;

On a Supabase project running pg_net 0.20.0, this is what we see:

net.http_request_queue  {supabase_admin=arwdDxtm/supabase_admin,=arwdDxtm/supabase_admin}
net._http_response      {supabase_admin=arwdDxtm/supabase_admin,=arwdDxtm/supabase_admin}
schema net              {..., =U/supabase_admin, ...}

So every role in the database, including anon and authenticated, can do the following:

  • INSERT into net.http_request_queue, which makes the database send arbitrary HTTP requests.
  • SELECT from net._http_response, which can expose other callers' response bodies and headers.
  • UPDATE, DELETE and TRUNCATE either table.

For anon and authenticated, PostgREST only reaches this if net is in the exposed schemas. But any role with a SQL session gets it: a custom role, or a SECURITY INVOKER function running as the caller.

Why project owners can't fix it themselves

  • The grant goes to PUBLIC and comes from the extension's install script. Supabase's extensions.grant_pg_net_access() event trigger grants to named roles only.
  • revoke ... from PUBLIC as postgres has no effect: supabase_admin granted it, and only the grantor can revoke.
  • Since 0.12.0, net.http_get and net.http_post are SECURITY INVOKER, so the roles that legitimately enqueue requests (postgres, supabase_functions_admin, service_role) rely on that same grant. A blanket revoke would break them unless they get explicit grants.

Our workaround is a BEFORE INSERT OR UPDATE OR DELETE trigger plus a statement-level TRUNCATE trigger on net.http_request_queue that reject any role not on an allow-list. It works, but it's a band-aid on every project.

Ask

Could the install and upgrade scripts grant to named roles instead of PUBLIC? For example, postgres, supabase_functions_admin and service_role, which the Supabase event trigger already handles. Failing that, could project owners be allowed to revoke the PUBLIC grant?

Environment: Supabase hosted, Postgres 17.6, pg_net 0.20.0.

Dominant language
Python
Stars
376
Forks
44
Avg merge
5d 11h
Merged PRs (30d)
16

Getting set up

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from supabase/pg_net

All issues in supabase/pg_net

Similar issues

More Python issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.