TL;DR
In ghcr.io/supabase/postgres:17.6.1.106, calling any function on which EXECUTE has been revoked from authenticated (or anon) crashes the backend with signal 11: Segmentation fault instead of raising 42501 permission denied for function. The previous image 17.6.1.095 raises the error correctly. The crash brings the entire Postgres instance into recovery mode, breaking all subsequent connections.
This appears to be in supautils' permission-denied path for reserved/hint_roles. It does not reproduce when the same operation is attempted by a non-reserved role.
Environment
- Image:
ghcr.io/supabase/postgres:17.6.1.106 (also reproduces under public.ecr.aws/supabase/postgres:17.6.1.106)
- Server:
PostgreSQL 17.6 on aarch64-unknown-linux-gnu, compiled by gcc (GCC) 15.2.0, 64-bit
- Supabase CLI:
2.90.0
- Started via:
supabase start (default config, no extra extensions enabled in supabase/config.toml)
shared_preload_libraries: pg_stat_statements, pgaudit, plpgsql, plpgsql_check, pg_cron, pg_net, pgsodium, auto_explain, pg_tle, plan_filter, supabase_vault
supautils.hint_roles: anon, authenticated, service_role
supautils.reserved_roles includes authenticated*, anon*, service_role*
Minimal reproduction
-- Trivial function, default search_path, security invoker — content is irrelevant.
create or replace function public.repro()
returns int
language sql
as $$ select 1; $$;
revoke all on function public.repro() from public, anon, authenticated;
set role authenticated;
select public.repro();
Expected
ERROR: permission denied for function repro
Actual
server closed the connection unexpectedly
This probably means the server terminated abnormally
before or while processing the request.
connection to server was lost
Postgres logs:
LOG: server process (PID 836) was terminated by signal 11: Segmentation fault
DETAIL: Failed process was running: select public.repro();
LOG: terminating any other active server processes
LOG: all server processes terminated; reinitializing
LOG: database system was not properly shut down; automatic recovery in progress
After recovery, all subsequent connections fail with FATAL: the database system is in recovery mode until Postgres finishes recovery.
Scope
Reproduces on:
set role authenticated; select public.<revoked_fn>();
set role anon; select public.<revoked_fn>();
- Both
SECURITY DEFINER and SECURITY INVOKER functions
- Functions whose body is trivially
select 1; — body is never executed
Does not reproduce on:
set role service_role; select public.<revoked_fn>(); (function executes normally; service_role wasn't denied)
- A non-reserved login role with the same revoke (
create role test_revoke_user login; grant test_revoke_user to postgres; set role test_revoke_user; select public.<revoked_fn>();) — this correctly raises ERROR: permission denied for function.
The differentiating factor between crash and clean error is whether the calling role is one of the supautils-managed reserved/hint_roles.
Regression range
| Image |
Behavior |
17.6.1.095 |
Clean 42501 permission denied |
17.6.1.106 |
SIGSEGV, full instance recovery cycle |
17.6.1.095 was the default for at least Supabase CLI versions through ~2.89.x; 2.90.0 defaults to 17.6.1.106. CI using supabase/setup-cli@v1 with version: latest started failing the moment the bump landed.
Real-world impact in our repo
Every pgTAP test of the form
set local role authenticated;
select throws_ok(
$$ select public.<service_role_only_rpc>(...) $$,
'42501', null,
'authenticated cannot execute <rpc>'
);
crashes the backend, takes down the entire test run, and leaves Postgres in recovery for several seconds. Every PR's supabase test db job has been failing since the image bump.
TL;DR
In
ghcr.io/supabase/postgres:17.6.1.106, calling any function on whichEXECUTEhas been revoked fromauthenticated(oranon) crashes the backend withsignal 11: Segmentation faultinstead of raising42501 permission denied for function. The previous image17.6.1.095raises the error correctly. The crash brings the entire Postgres instance into recovery mode, breaking all subsequent connections.This appears to be in
supautils' permission-denied path for reserved/hint_roles. It does not reproduce when the same operation is attempted by a non-reserved role.Environment
ghcr.io/supabase/postgres:17.6.1.106(also reproduces underpublic.ecr.aws/supabase/postgres:17.6.1.106)PostgreSQL 17.6 on aarch64-unknown-linux-gnu, compiled by gcc (GCC) 15.2.0, 64-bit2.90.0supabase start(default config, no extra extensions enabled insupabase/config.toml)shared_preload_libraries:pg_stat_statements, pgaudit, plpgsql, plpgsql_check, pg_cron, pg_net, pgsodium, auto_explain, pg_tle, plan_filter, supabase_vaultsupautils.hint_roles:anon, authenticated, service_rolesupautils.reserved_rolesincludesauthenticated*, anon*, service_role*Minimal reproduction
Expected
Actual
Postgres logs:
After recovery, all subsequent connections fail with
FATAL: the database system is in recovery modeuntil Postgres finishes recovery.Scope
Reproduces on:
set role authenticated; select public.<revoked_fn>();set role anon; select public.<revoked_fn>();SECURITY DEFINERandSECURITY INVOKERfunctionsselect 1;— body is never executedDoes not reproduce on:
set role service_role; select public.<revoked_fn>();(function executes normally; service_role wasn't denied)create role test_revoke_user login; grant test_revoke_user to postgres; set role test_revoke_user; select public.<revoked_fn>();) — this correctly raisesERROR: permission denied for function.The differentiating factor between crash and clean error is whether the calling role is one of the supautils-managed reserved/
hint_roles.Regression range
17.6.1.09542501 permission denied17.6.1.10617.6.1.095was the default for at least Supabase CLI versions through ~2.89.x;2.90.0defaults to17.6.1.106. CI usingsupabase/setup-cli@v1withversion: lateststarted failing the moment the bump landed.Real-world impact in our repo
Every pgTAP test of the form
crashes the backend, takes down the entire test run, and leaves Postgres in recovery for several seconds. Every PR's
supabase test dbjob has been failing since the image bump.