Summary
On ghcr.io/supabase/postgres:17.6.1.106, a DO block that does SET LOCAL ROLE
to an unprivileged role and then EXECUTEs a call to a SECURITY DEFINER
PL/pgSQL function that role cannot execute, with all-NULL arguments,
terminates the backend with SIGSEGV instead of raising insufficient_privilege
(42501).
The postmaster then terminates every other backend and enters recovery, so all
concurrent work on the server is lost.
This does not reproduce on upstream PostgreSQL 17.10, nor on Supabase's
managed PostgreSQL 17.6.
Reproduction
create role lowpriv nologin;
create table t_events(a text, b text, c text, d uuid, e text, f timestamptz, g text);
create table t_rows(id text, status text);
create or replace function public.f_definer(
p1 text, p2 text, p3 text, p4 uuid, p5 text, p6 timestamptz, p7 text)
returns void language plpgsql security definer set search_path = public as $$
declare v text;
begin
if exists (select 1 from public.t_events where b = p2 and c = p3) then return; end if;
select status into v from public.t_rows where id = p2;
insert into public.t_events(a,b,c,d,e,f,g)
values (p1,p2,p3,p4,coalesce(p5,'x'),coalesce(p6,now()),coalesce(p7,'y'));
end $$;
revoke all on function public.f_definer(text,text,text,uuid,text,timestamptz,text)
from public, lowpriv;
begin;
do $$
begin
set local role lowpriv;
begin
execute 'select public.f_definer(null,null,null,null,null,null,null)';
reset role;
exception
when insufficient_privilege then reset role;
when others then reset role;
end;
end $$;
rollback;
Expected: insufficient_privilege is caught; transaction rolls back.
Actual: backend segfaults.
Server log
LOG: server process (PID 283) was terminated by signal 11: Segmentation fault
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
FATAL: the database system is in recovery mode
Environment matrix
| Environment |
Version |
Build / arch |
Transport |
Result |
ghcr.io/supabase/postgres:17.6.1.106 |
17.6 |
GCC 15.2.0 · x86_64 |
psql |
SEGFAULT |
| Supabase managed |
17.6 |
GCC 15.2.0 · aarch64 |
Management API |
survives (42501) |
| Upstream Homebrew |
17.10 |
Apple clang 21 · aarch64 |
psql |
survives (42501) |
Ruled out
- Extensions.
pg_net 0.20.0 and pg_graphql 1.5.11 were dropped so the set
matched the managed instance exactly (btree_gist, pg_stat_statements,
pgcrypto, plpgsql, supabase_vault, uuid-ossp). Still crashes.
- Test framework. The script above runs standalone under
psql.
- Transport. Upstream 17.10 survives the identical sequence over the same
psql connection.
Not isolated
Architecture (x86_64 vs aarch64), patch version (17.6 vs 17.10), and the
Supabase build vs upstream remain confounded — separating them needs an aarch64
build of the same image, or an x86_64 upstream 17.6.
Impact
A permission check that segfaults is a denial-of-service vector: any role able to
attempt an unauthorised call can restart the database. Found by a security test
that asserts revoked functions are refused.
Summary
On
ghcr.io/supabase/postgres:17.6.1.106, aDOblock that doesSET LOCAL ROLEto an unprivileged role and then
EXECUTEs a call to aSECURITY DEFINERPL/pgSQL function that role cannot execute, with all-
NULLarguments,terminates the backend with SIGSEGV instead of raising
insufficient_privilege(42501).
The postmaster then terminates every other backend and enters recovery, so all
concurrent work on the server is lost.
This does not reproduce on upstream PostgreSQL 17.10, nor on Supabase's
managed PostgreSQL 17.6.
Reproduction
Expected:
insufficient_privilegeis caught; transaction rolls back.Actual: backend segfaults.
Server log
Environment matrix
ghcr.io/supabase/postgres:17.6.1.106Ruled out
pg_net 0.20.0andpg_graphql 1.5.11were dropped so the setmatched the managed instance exactly (
btree_gist,pg_stat_statements,pgcrypto,plpgsql,supabase_vault,uuid-ossp). Still crashes.psql.psql connection.
Not isolated
Architecture (x86_64 vs aarch64), patch version (17.6 vs 17.10), and the
Supabase build vs upstream remain confounded — separating them needs an aarch64
build of the same image, or an x86_64 upstream 17.6.
Impact
A permission check that segfaults is a denial-of-service vector: any role able to
attempt an unauthorised call can restart the database. Found by a security test
that asserts revoked functions are refused.