diff --git a/lints/0028_anon_security_definer_function_executable.sql b/lints/0028_anon_security_definer_function_executable.sql index ac47354..39f3385 100644 --- a/lints/0028_anon_security_definer_function_executable.sql +++ b/lints/0028_anon_security_definer_function_executable.sql @@ -60,6 +60,10 @@ from on p.prolang = l.oid where p.prosecdef = true + -- PostgREST only exposes ordinary functions: procedures are not + -- callable via /rpc, and neither are trigger functions. + and p.prokind = 'f' + and p.prorettype <> 'pg_catalog.trigger'::regtype and pg_catalog.has_function_privilege('anon', p.oid, 'EXECUTE') and n.nspname = any(array(select trim(unnest(string_to_array(coalesce(current_setting('pgrst.db_schemas', 't'), 'public'), ','))))) and n.nspname not in ( diff --git a/lints/0029_authenticated_security_definer_function_executable.sql b/lints/0029_authenticated_security_definer_function_executable.sql index a000895..5383f03 100644 --- a/lints/0029_authenticated_security_definer_function_executable.sql +++ b/lints/0029_authenticated_security_definer_function_executable.sql @@ -61,6 +61,10 @@ from on p.prolang = l.oid where p.prosecdef = true + -- PostgREST only exposes ordinary functions: procedures are not + -- callable via /rpc, and neither are trigger functions. + and p.prokind = 'f' + and p.prorettype <> 'pg_catalog.trigger'::regtype and pg_catalog.has_function_privilege('authenticated', p.oid, 'EXECUTE') and n.nspname = any(array(select trim(unnest(string_to_array(coalesce(current_setting('pgrst.db_schemas', 't'), 'public'), ','))))) and n.nspname not in ( diff --git a/splinter.sql b/splinter.sql index 46bb331..622f484 100644 --- a/splinter.sql +++ b/splinter.sql @@ -1756,6 +1756,10 @@ from on p.prolang = l.oid where p.prosecdef = true + -- PostgREST only exposes ordinary functions: procedures are not + -- callable via /rpc, and neither are trigger functions. + and p.prokind = 'f' + and p.prorettype <> 'pg_catalog.trigger'::regtype and pg_catalog.has_function_privilege('anon', p.oid, 'EXECUTE') and n.nspname = any(array(select trim(unnest(string_to_array(coalesce(current_setting('pgrst.db_schemas', 't'), 'public'), ','))))) and n.nspname not in ( @@ -1829,6 +1833,10 @@ from on p.prolang = l.oid where p.prosecdef = true + -- PostgREST only exposes ordinary functions: procedures are not + -- callable via /rpc, and neither are trigger functions. + and p.prokind = 'f' + and p.prorettype <> 'pg_catalog.trigger'::regtype and pg_catalog.has_function_privilege('authenticated', p.oid, 'EXECUTE') and n.nspname = any(array(select trim(unnest(string_to_array(coalesce(current_setting('pgrst.db_schemas', 't'), 'public'), ','))))) and n.nspname not in ( diff --git a/test/expected/0028_anon_security_definer_function_executable.out b/test/expected/0028_anon_security_definer_function_executable.out index d9cc472..9cadb2a 100644 --- a/test/expected/0028_anon_security_definer_function_executable.out +++ b/test/expected/0028_anon_security_definer_function_executable.out @@ -121,4 +121,30 @@ begin; (0 rows) rollback to savepoint case_system_schema; + savepoint case_not_rpc_callable; + ---------------------------------------- + -- NEGATIVE: procedures are not exposed by PostgREST, so a + -- SECURITY DEFINER procedure must not be reported as callable via + -- /rest/v1/rpc. + ---------------------------------------- + create procedure public.secdef_proc() language sql security definer + as $$ select 1 $$; + select * from lint."0028_anon_security_definer_function_executable"; + name | title | level | facing | categories | description | detail | remediation | metadata | cache_key +------+-------+-------+--------+------------+-------------+--------+-------------+----------+----------- +(0 rows) + + ---------------------------------------- + -- NEGATIVE: trigger functions return trigger and are not exposed + -- as RPC endpoints either. + ---------------------------------------- + create function public.secdef_trigger() returns trigger + language plpgsql security definer + as $$ begin return new; end $$; + select * from lint."0028_anon_security_definer_function_executable"; + name | title | level | facing | categories | description | detail | remediation | metadata | cache_key +------+-------+-------+--------+------------+-------------+--------+-------------+----------+----------- +(0 rows) + + rollback to savepoint case_not_rpc_callable; rollback; diff --git a/test/expected/0029_authenticated_security_definer_function_executable.out b/test/expected/0029_authenticated_security_definer_function_executable.out index 7f00993..33bb073 100644 --- a/test/expected/0029_authenticated_security_definer_function_executable.out +++ b/test/expected/0029_authenticated_security_definer_function_executable.out @@ -117,4 +117,30 @@ begin; (0 rows) rollback to savepoint case_system_schema; + savepoint case_not_rpc_callable; + ---------------------------------------- + -- NEGATIVE: procedures are not exposed by PostgREST, so a + -- SECURITY DEFINER procedure must not be reported as callable via + -- /rest/v1/rpc. + ---------------------------------------- + create procedure public.secdef_proc() language sql security definer + as $$ select 1 $$; + select * from lint."0029_authenticated_security_definer_function_executable"; + name | title | level | facing | categories | description | detail | remediation | metadata | cache_key +------+-------+-------+--------+------------+-------------+--------+-------------+----------+----------- +(0 rows) + + ---------------------------------------- + -- NEGATIVE: trigger functions return trigger and are not exposed + -- as RPC endpoints either. + ---------------------------------------- + create function public.secdef_trigger() returns trigger + language plpgsql security definer + as $$ begin return new; end $$; + select * from lint."0029_authenticated_security_definer_function_executable"; + name | title | level | facing | categories | description | detail | remediation | metadata | cache_key +------+-------+-------+--------+------------+-------------+--------+-------------+----------+----------- +(0 rows) + + rollback to savepoint case_not_rpc_callable; rollback; diff --git a/test/sql/0028_anon_security_definer_function_executable.sql b/test/sql/0028_anon_security_definer_function_executable.sql index 1011918..7b510a8 100644 --- a/test/sql/0028_anon_security_definer_function_executable.sql +++ b/test/sql/0028_anon_security_definer_function_executable.sql @@ -110,4 +110,26 @@ begin; rollback to savepoint case_system_schema; + savepoint case_not_rpc_callable; + + ---------------------------------------- + -- NEGATIVE: procedures are not exposed by PostgREST, so a + -- SECURITY DEFINER procedure must not be reported as callable via + -- /rest/v1/rpc. + ---------------------------------------- + create procedure public.secdef_proc() language sql security definer + as $$ select 1 $$; + select * from lint."0028_anon_security_definer_function_executable"; + + ---------------------------------------- + -- NEGATIVE: trigger functions return trigger and are not exposed + -- as RPC endpoints either. + ---------------------------------------- + create function public.secdef_trigger() returns trigger + language plpgsql security definer + as $$ begin return new; end $$; + select * from lint."0028_anon_security_definer_function_executable"; + + rollback to savepoint case_not_rpc_callable; + rollback; diff --git a/test/sql/0029_authenticated_security_definer_function_executable.sql b/test/sql/0029_authenticated_security_definer_function_executable.sql index 1004bef..f029a60 100644 --- a/test/sql/0029_authenticated_security_definer_function_executable.sql +++ b/test/sql/0029_authenticated_security_definer_function_executable.sql @@ -105,4 +105,26 @@ begin; rollback to savepoint case_system_schema; + savepoint case_not_rpc_callable; + + ---------------------------------------- + -- NEGATIVE: procedures are not exposed by PostgREST, so a + -- SECURITY DEFINER procedure must not be reported as callable via + -- /rest/v1/rpc. + ---------------------------------------- + create procedure public.secdef_proc() language sql security definer + as $$ select 1 $$; + select * from lint."0029_authenticated_security_definer_function_executable"; + + ---------------------------------------- + -- NEGATIVE: trigger functions return trigger and are not exposed + -- as RPC endpoints either. + ---------------------------------------- + create function public.secdef_trigger() returns trigger + language plpgsql security definer + as $$ begin return new; end $$; + select * from lint."0029_authenticated_security_definer_function_executable"; + + rollback to savepoint case_not_rpc_callable; + rollback;