Initial Docker Postgres schema has potential security issues
dsyrstad opened this issue · comments
Bug report
Describe the bug
The initial postgres initialization files for self-hosted docker installations located in https://github.com/supabase/supabase/tree/master/docker/volumes/db/init allows wide access to the public
schema. For example, https://github.com/supabase/supabase/blob/master/docker/volumes/db/init/00-initial-schema.sql doesn't lock down the public schema and allows the authenticated
and anon
roles to create tables, functions, and even operators in public
.
A possible security hole this could open is described here: https://www.cybertec-postgresql.com/en/abusing-security-definer-functions/
To Reproduce
Run the following SQL (this will run under the authenticated
role):
set role authenticated;
drop operator if exists public.+ (integer, integer);
drop function if exists public.sum;
CREATE FUNCTION public.sum(integer, integer) RETURNS integer
LANGUAGE sql AS
'ALTER ROLE authenticated SUPERUSER; SELECT $1 OPERATOR(pg_catalog.+) $2';
CREATE OPERATOR public.+ (
FUNCTION = public.sum,
LEFTARG = integer,
RIGHTARG = integer
);
The authenticated
role has now redefined the +
operator. Any function running with SECURITY DEFINER
privilege which uses the +
operator will grant the authenticated
role superuser
privileges.
Expected behavior
At minimum, all DDL access should be revoked from authenticated
and anon
. A better catch-all policy would be to revoke everything from authenticated
and anon
for the public
schema and require that the app explicitly grants access to individual tables and functions.
Other information
One could argue that an authenticated
user shouldn't be able to issue the above SQL in the context of a vanilla Postgrest API, but Postgrest allows rpc calls which could open up the possibility of SQL injection attacks if the rpc function uses dynamic SQL. Even if an rpc function is executed as security invoker
, it would be sufficient to allow the two CREATE
statements above to succeed.
I've transferred this issue to postgres repo since the schema migrations are now managed from there.
@staaldraad could you please evaluate this one and lmk if we need to adjust anything
I don't think this is an issue since self hosted so users reasonably need to administer their project and authenticated
and anon
don't have SQL access but would appreciate your take
Agree with @olirice.
Furthermore, this would require a vulnerable function that is SECURITY DEFINER
, owned by a superuser
and has a mutable search_path
. We already warn against this (mutable search path) via supabase/splinter https://github.com/supabase/splinter/blob/main/docs/0011_function_search_path_mutable.md
From PG15, the public schema is default protected, so this is also no longer possible from the authenticated
user. postgres
user can do this, but that implies full DB access already (minus superuser, but then again relies on the aforementioned security issue in a misconfigured function)
postgres=> set role authenticated;
SET
postgres=> CREATE FUNCTION public.sum(integer, integer) RETURNS integer
LANGUAGE sql AS
'ALTER ROLE authenticated SUPERUSER; SELECT $1 OPERATOR(pg_catalog.+) $2';
ERROR: permission denied for schema public
postgres=> set role postgres;
SET
postgres=> CREATE FUNCTION public.sum(integer, integer) RETURNS integer
LANGUAGE sql AS
'ALTER ROLE authenticated SUPERUSER; SELECT $1 OPERATOR(pg_catalog.+) $2';
CREATE FUNCTION
postgres=> select version();
version
-----------------------------------------------------------------------------------------------------------------------------------------
PostgreSQL 15.1 (Ubuntu 15.1-1.pgdg20.04+1) on aarch64-unknown-linux-gnu, compiled by gcc (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0, 64-bit
(1 row)
thanks! closing as addressed