Skip to content

Commit 52ac42e

Browse files
authored
fix: prevent non-superuser roles from dropping supabase_privileged_role (#2150)
Add supabase_privileged_role to supautils.reserved_roles so non-superusers with CREATEROLE cannot drop it on PG 15, where PG's native ADMIN OPTION check (introduced in PG 16) does not apply. PG 16+ requires ADMIN OPTION to drop a non-superuser role: https://github.com/postgres/postgres/blame/REL_16_STABLE/src/backend/commands/user.c#L1175 This check is absent in PG 15: https://github.com/postgres/postgres/blob/REL_15_STABLE/src/backend/commands/user.c#L986 Fixes: https://linear.app/supabase/issue/PSQL-1205
1 parent 60c9ee9 commit 52ac42e

3 files changed

Lines changed: 34 additions & 1 deletion

File tree

ansible/files/postgresql_config/supautils.conf.j2

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,5 @@ supautils.privileged_extensions_superuser = 'supabase_admin'
1212
supautils.privileged_role = 'supabase_privileged_role'
1313
supautils.privileged_role_allowed_configs = 'auto_explain.*, deadlock_timeout, log_lock_waits, log_min_duration_statement, log_min_messages, log_parameter_max_length, log_replication_commands, log_statement, log_temp_files, pg_net.batch_size, pg_net.ttl, pg_stat_statements.*, pgaudit.log, pgaudit.log_catalog, pgaudit.log_client, pgaudit.log_level, pgaudit.log_relation, pgaudit.log_rows, pgaudit.log_statement, pgaudit.log_statement_once, pgaudit.role, pgrst.*, plan_filter.*, safeupdate.enabled, session_replication_role, track_functions, track_io_timing, wal_compression'
1414
supautils.reserved_memberships = 'pg_read_server_files, pg_write_server_files, pg_execute_server_program, supabase_admin, supabase_auth_admin, supabase_storage_admin, supabase_read_only_user, supabase_realtime_admin, supabase_replication_admin, supabase_etl_admin, dashboard_user, pgbouncer, authenticator'
15-
supautils.reserved_roles = 'supabase_admin, supabase_auth_admin, supabase_storage_admin, supabase_read_only_user, supabase_realtime_admin, supabase_replication_admin, supabase_etl_admin, dashboard_user, pgbouncer, service_role*, authenticator*, authenticated*, anon*'
15+
supautils.reserved_roles = 'supabase_admin, supabase_auth_admin, supabase_storage_admin, supabase_read_only_user, supabase_realtime_admin, supabase_replication_admin, supabase_etl_admin, dashboard_user, pgbouncer, service_role*, authenticator*, authenticated*, anon*, supabase_privileged_role'
1616
supautils.hint_roles = 'anon, authenticated, service_role'
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
-- verify non-superuser postgres role cannot drop supabase_privileged_role
2+
BEGIN;
3+
-- Switch to the postgres role (non-superuser) to test supautils behavior
4+
SET ROLE postgres;
5+
-- SAVEPOINT is needed to recover from the expected error and continue the transaction
6+
SAVEPOINT before_drop;
7+
DROP ROLE supabase_privileged_role;
8+
ERROR: "supabase_privileged_role" is a reserved role, only superusers can modify it
9+
ROLLBACK TO SAVEPOINT before_drop;
10+
RESET ROLE;
11+
SELECT rolname FROM pg_roles WHERE rolname = 'supabase_privileged_role';
12+
rolname
13+
--------------------------
14+
supabase_privileged_role
15+
(1 row)
16+
17+
ROLLBACK;
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
-- verify non-superuser postgres role cannot drop supabase_privileged_role
2+
BEGIN;
3+
4+
-- Switch to the postgres role (non-superuser) to test supautils behavior
5+
SET ROLE postgres;
6+
7+
-- SAVEPOINT is needed to recover from the expected error and continue the transaction
8+
SAVEPOINT before_drop;
9+
DROP ROLE supabase_privileged_role;
10+
ROLLBACK TO SAVEPOINT before_drop;
11+
12+
RESET ROLE;
13+
14+
SELECT rolname FROM pg_roles WHERE rolname = 'supabase_privileged_role';
15+
16+
ROLLBACK;

0 commit comments

Comments
 (0)