Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions lints/0003_auth_rls_initplan.sql
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,10 @@ from
policies
where
is_rls_active
-- NOTE: does not include realtime in support of monitoring policies on realtime.messages
-- NOTE: does not include realtime or storage in support of monitoring user-authored
-- policies on realtime.messages and storage.objects
and schema_name not in (
'_timescaledb_cache', '_timescaledb_catalog', '_timescaledb_config', '_timescaledb_internal', 'auth', 'cron', 'extensions', 'graphql', 'graphql_public', 'information_schema', 'net', 'pgmq', 'pgroonga', 'pgsodium', 'pgsodium_masks', 'pgtle', 'pgbouncer', 'pg_catalog', 'repack', 'storage', 'supabase_functions', 'supabase_migrations', 'tiger', 'topology', 'vault'
'_timescaledb_cache', '_timescaledb_catalog', '_timescaledb_config', '_timescaledb_internal', 'auth', 'cron', 'extensions', 'graphql', 'graphql_public', 'information_schema', 'net', 'pgmq', 'pgroonga', 'pgsodium', 'pgsodium_masks', 'pgtle', 'pgbouncer', 'pg_catalog', 'repack', 'supabase_functions', 'supabase_migrations', 'tiger', 'topology', 'vault'
)
and (
-- Example: auth.uid()
Expand Down
2 changes: 1 addition & 1 deletion lints/0006_multiple_permissive_policies.sql
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ where
c.relkind = 'r' -- regular tables
and p.polpermissive -- policy is permissive
and n.nspname not in (
'_timescaledb_cache', '_timescaledb_catalog', '_timescaledb_config', '_timescaledb_internal', 'auth', 'cron', 'extensions', 'graphql', 'graphql_public', 'information_schema', 'net', 'pgmq', 'pgroonga', 'pgsodium', 'pgsodium_masks', 'pgtle', 'pgbouncer', 'pg_catalog', 'realtime', 'repack', 'storage', 'supabase_functions', 'supabase_migrations', 'tiger', 'topology', 'vault'
'_timescaledb_cache', '_timescaledb_catalog', '_timescaledb_config', '_timescaledb_internal', 'auth', 'cron', 'extensions', 'graphql', 'graphql_public', 'information_schema', 'net', 'pgmq', 'pgroonga', 'pgsodium', 'pgsodium_masks', 'pgtle', 'pgbouncer', 'pg_catalog', 'realtime', 'repack', 'supabase_functions', 'supabase_migrations', 'tiger', 'topology', 'vault'
)
and r.rolname not like 'pg_%'
and r.rolname not like 'supabase%admin'
Expand Down
2 changes: 1 addition & 1 deletion lints/0015_rls_references_user_metadata.sql
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ from
policies
where
schema_name not in (
'_timescaledb_cache', '_timescaledb_catalog', '_timescaledb_config', '_timescaledb_internal', 'auth', 'cron', 'extensions', 'graphql', 'graphql_public', 'information_schema', 'net', 'pgmq', 'pgroonga', 'pgsodium', 'pgsodium_masks', 'pgtle', 'pgbouncer', 'pg_catalog', 'realtime', 'repack', 'storage', 'supabase_functions', 'supabase_migrations', 'tiger', 'topology', 'vault'
'_timescaledb_cache', '_timescaledb_catalog', '_timescaledb_config', '_timescaledb_internal', 'auth', 'cron', 'extensions', 'graphql', 'graphql_public', 'information_schema', 'net', 'pgmq', 'pgroonga', 'pgsodium', 'pgsodium_masks', 'pgtle', 'pgbouncer', 'pg_catalog', 'repack', 'supabase_functions', 'supabase_migrations', 'tiger', 'topology', 'vault'
)
and (
-- Example: auth.jwt() -> 'user_metadata'
Expand Down
9 changes: 5 additions & 4 deletions splinter.sql
Original file line number Diff line number Diff line change
Expand Up @@ -241,9 +241,10 @@ from
policies
where
is_rls_active
-- NOTE: does not include realtime in support of monitoring policies on realtime.messages
-- NOTE: does not include realtime or storage in support of monitoring user-authored
-- policies on realtime.messages and storage.objects
and schema_name not in (
'_timescaledb_cache', '_timescaledb_catalog', '_timescaledb_config', '_timescaledb_internal', 'auth', 'cron', 'extensions', 'graphql', 'graphql_public', 'information_schema', 'net', 'pgmq', 'pgroonga', 'pgsodium', 'pgsodium_masks', 'pgtle', 'pgbouncer', 'pg_catalog', 'repack', 'storage', 'supabase_functions', 'supabase_migrations', 'tiger', 'topology', 'vault'
'_timescaledb_cache', '_timescaledb_catalog', '_timescaledb_config', '_timescaledb_internal', 'auth', 'cron', 'extensions', 'graphql', 'graphql_public', 'information_schema', 'net', 'pgmq', 'pgroonga', 'pgsodium', 'pgsodium_masks', 'pgtle', 'pgbouncer', 'pg_catalog', 'repack', 'supabase_functions', 'supabase_migrations', 'tiger', 'topology', 'vault'
)
and (
-- Example: auth.uid()
Expand Down Expand Up @@ -440,7 +441,7 @@ where
c.relkind = 'r' -- regular tables
and p.polpermissive -- policy is permissive
and n.nspname not in (
'_timescaledb_cache', '_timescaledb_catalog', '_timescaledb_config', '_timescaledb_internal', 'auth', 'cron', 'extensions', 'graphql', 'graphql_public', 'information_schema', 'net', 'pgmq', 'pgroonga', 'pgsodium', 'pgsodium_masks', 'pgtle', 'pgbouncer', 'pg_catalog', 'realtime', 'repack', 'storage', 'supabase_functions', 'supabase_migrations', 'tiger', 'topology', 'vault'
'_timescaledb_cache', '_timescaledb_catalog', '_timescaledb_config', '_timescaledb_internal', 'auth', 'cron', 'extensions', 'graphql', 'graphql_public', 'information_schema', 'net', 'pgmq', 'pgroonga', 'pgsodium', 'pgsodium_masks', 'pgtle', 'pgbouncer', 'pg_catalog', 'realtime', 'repack', 'supabase_functions', 'supabase_migrations', 'tiger', 'topology', 'vault'
)
and r.rolname not like 'pg_%'
and r.rolname not like 'supabase%admin'
Expand Down Expand Up @@ -821,7 +822,7 @@ from
policies
where
schema_name not in (
'_timescaledb_cache', '_timescaledb_catalog', '_timescaledb_config', '_timescaledb_internal', 'auth', 'cron', 'extensions', 'graphql', 'graphql_public', 'information_schema', 'net', 'pgmq', 'pgroonga', 'pgsodium', 'pgsodium_masks', 'pgtle', 'pgbouncer', 'pg_catalog', 'realtime', 'repack', 'storage', 'supabase_functions', 'supabase_migrations', 'tiger', 'topology', 'vault'
'_timescaledb_cache', '_timescaledb_catalog', '_timescaledb_config', '_timescaledb_internal', 'auth', 'cron', 'extensions', 'graphql', 'graphql_public', 'information_schema', 'net', 'pgmq', 'pgroonga', 'pgsodium', 'pgsodium_masks', 'pgtle', 'pgbouncer', 'pg_catalog', 'repack', 'supabase_functions', 'supabase_migrations', 'tiger', 'topology', 'vault'
)
and (
-- Example: auth.jwt() -> 'user_metadata'
Expand Down
30 changes: 30 additions & 0 deletions test/expected/0003_auth_rls_initplan.out
Original file line number Diff line number Diff line change
Expand Up @@ -90,4 +90,34 @@ begin;
auth_rls_initplan | Auth RLS Initialization Plan | WARN | EXTERNAL | {PERFORMANCE} | Detects if calls to \`current_setting()\` and \`auth.<function>()\` in RLS policies are being unnecessarily re-evaluated for each row | Table \`realtime.messages\` has a row level security policy \`realtime_check\` that re-evaluates current_setting() or auth.<function>() for each row. This produces suboptimal query performance at scale. Resolve the issue by replacing \`auth.<function>()\` with \`(select auth.<function>())\`. See [docs](https://supabase.com/docs/guides/database/postgres/row-level-security#call-functions-with-select) for more info. | https://supabase.com/docs/guides/database/database-linter?lint=0003_auth_rls_initplan | {"name": "messages", "type": "table", "schema": "realtime"} | auth_rls_init_plan_realtime_messages_realtime_check
(1 row)

rollback to savepoint a;
-- Confirm that storage.objects will be scanned (#35)
create schema storage;
create table storage.objects( id int primary key, owner uuid);
create policy storage_owner_check on storage.objects
for select
to authenticated
using (owner = auth.uid());
alter table storage.objects enable row level security;
-- 1 entry for storage.objects
select * from lint."0003_auth_rls_initplan";
name | title | level | facing | categories | description | detail | remediation | metadata | cache_key
-------------------+------------------------------+-------+----------+---------------+---------------------------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------+-----------------------------------------------------------+--------------------------------------------------------
auth_rls_initplan | Auth RLS Initialization Plan | WARN | EXTERNAL | {PERFORMANCE} | Detects if calls to \`current_setting()\` and \`auth.<function>()\` in RLS policies are being unnecessarily re-evaluated for each row | Table \`storage.objects\` has a row level security policy \`storage_owner_check\` that re-evaluates current_setting() or auth.<function>() for each row. This produces suboptimal query performance at scale. Resolve the issue by replacing \`auth.<function>()\` with \`(select auth.<function>())\`. See [docs](https://supabase.com/docs/guides/database/postgres/row-level-security#call-functions-with-select) for more info. | https://supabase.com/docs/guides/database/database-linter?lint=0003_auth_rls_initplan | {"name": "objects", "type": "table", "schema": "storage"} | auth_rls_init_plan_storage_objects_storage_owner_check
(1 row)

rollback to savepoint a;
-- auth remains excluded: users do not author policies there
create table auth.sessions( id int primary key, user_id uuid);
create policy auth_sessions_check on auth.sessions
for select
to authenticated
using (user_id = auth.uid());
alter table auth.sessions enable row level security;
-- No issues
select * from lint."0003_auth_rls_initplan";
name | title | level | facing | categories | description | detail | remediation | metadata | cache_key
------+-------+-------+--------+------------+-------------+--------+-------------+----------+-----------
(0 rows)

rollback;
43 changes: 43 additions & 0 deletions test/expected/0006_multiple_permissive_policies.out
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,49 @@ begin;
select * from lint."0006_multiple_permissive_policies";
name | title | level | facing | categories | description | detail | remediation | metadata | cache_key
------+-------+-------+--------+------------+-------------+--------+-------------+----------+-----------
(0 rows)

savepoint a;
-- Confirm that storage.objects will be scanned (#35)
create schema storage;
create table storage.objects(
id int primary key,
bucket_id text
);
alter table storage.objects enable row level security;
create policy avatars_read on storage.objects
for select
to authenticated
using (bucket_id = 'avatars');
create policy documents_read on storage.objects
for select
to authenticated
using (bucket_id = 'documents');
-- 1 entry for storage.objects, authenticated, SELECT
select * from lint."0006_multiple_permissive_policies";
name | title | level | facing | categories | description | detail | remediation | metadata | cache_key
------------------------------+------------------------------+-------+----------+---------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------+-----------------------------------------------------------+-------------------------------------------------------------------
multiple_permissive_policies | Multiple Permissive Policies | WARN | EXTERNAL | {PERFORMANCE} | Detects if multiple permissive row level security policies are present on a table for the same \`role\` and \`action\` (e.g. insert). Multiple permissive policies are suboptimal for performance as each policy must be executed for every relevant query. | Table \`storage.objects\` has multiple permissive policies for role \`authenticated\` for action \`SELECT\`. Policies include \`{avatars_read,documents_read}\` | https://supabase.com/docs/guides/database/database-linter?lint=0006_multiple_permissive_policies | {"name": "objects", "type": "table", "schema": "storage"} | multiple_permissive_policies_storage_objects_authenticated_SELECT
(1 row)

rollback to savepoint a;
-- auth remains excluded: users do not author policies there
create table auth.sessions(
id int primary key
);
alter table auth.sessions enable row level security;
create policy sessions_read_1 on auth.sessions
for select
to authenticated
using (true);
create policy sessions_read_2 on auth.sessions
for select
to authenticated
using (true);
-- No issues
select * from lint."0006_multiple_permissive_policies";
name | title | level | facing | categories | description | detail | remediation | metadata | cache_key
------+-------+-------+--------+------------+-------------+--------+-------------+----------+-----------
(0 rows)

rollback;
37 changes: 37 additions & 0 deletions test/expected/0015_rls_references_user_metadata.out
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,41 @@ begin;
rls_references_user_metadata | RLS references user metadata | ERROR | EXTERNAL | {SECURITY} | Detects when Supabase Auth user_metadata is referenced insecurely in a row level security (RLS) policy. | Table \`public.foo\` has a row level security policy \`bad_policy_2\` that references Supabase Auth \`user_metadata\`. \`user_metadata\` is editable by end users and should never be used in a security context. | https://supabase.com/docs/guides/database/database-linter?lint=0015_rls_references_user_metadata | {"name": "foo", "type": "table", "schema": "public"} | rls_references_user_metadata_public_foo_bad_policy_2
(2 rows)

savepoint a;
drop table public.foo;
-- Confirm that storage.objects and realtime.messages will be scanned (#35)
create schema storage;
create table storage.objects( id int primary key);
create policy storage_user_metadata on storage.objects
for select
to authenticated
using ( (( select auth.jwt() ) -> 'user_metadata' ->> 'is_admin' )::bool );
create schema realtime;
create table realtime.messages( id int primary key);
create policy realtime_user_metadata on realtime.messages
for select
to authenticated
using ( (( select auth.jwt() ) -> 'user_metadata' ->> 'is_admin' )::bool );
-- 2 errors, one each for storage.objects and realtime.messages
select * from lint."0015_rls_references_user_metadata";
name | title | level | facing | categories | description | detail | remediation | metadata | cache_key
------------------------------+------------------------------+-------+----------+------------+---------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------+-------------------------------------------------------------+-----------------------------------------------------------------------
rls_references_user_metadata | RLS references user metadata | ERROR | EXTERNAL | {SECURITY} | Detects when Supabase Auth user_metadata is referenced insecurely in a row level security (RLS) policy. | Table \`storage.objects\` has a row level security policy \`storage_user_metadata\` that references Supabase Auth \`user_metadata\`. \`user_metadata\` is editable by end users and should never be used in a security context. | https://supabase.com/docs/guides/database/database-linter?lint=0015_rls_references_user_metadata | {"name": "objects", "type": "table", "schema": "storage"} | rls_references_user_metadata_storage_objects_storage_user_metadata
rls_references_user_metadata | RLS references user metadata | ERROR | EXTERNAL | {SECURITY} | Detects when Supabase Auth user_metadata is referenced insecurely in a row level security (RLS) policy. | Table \`realtime.messages\` has a row level security policy \`realtime_user_metadata\` that references Supabase Auth \`user_metadata\`. \`user_metadata\` is editable by end users and should never be used in a security context. | https://supabase.com/docs/guides/database/database-linter?lint=0015_rls_references_user_metadata | {"name": "messages", "type": "table", "schema": "realtime"} | rls_references_user_metadata_realtime_messages_realtime_user_metadata
(2 rows)

rollback to savepoint a;
drop table public.foo;
-- auth remains excluded: users do not author policies there
create table auth.sessions( id int primary key);
create policy auth_user_metadata on auth.sessions
for select
to authenticated
using ( (( select auth.jwt() ) -> 'user_metadata' ->> 'is_admin' )::bool );
-- No issues
select * from lint."0015_rls_references_user_metadata";
name | title | level | facing | categories | description | detail | remediation | metadata | cache_key
------+-------+-------+--------+------------+-------------+--------+-------------+----------+-----------
(0 rows)

rollback;
31 changes: 31 additions & 0 deletions test/sql/0003_auth_rls_initplan.sql
Original file line number Diff line number Diff line change
Expand Up @@ -91,4 +91,35 @@ begin;
-- 1 entry for realtime.messages
select * from lint."0003_auth_rls_initplan";

rollback to savepoint a;

-- Confirm that storage.objects will be scanned (#35)
create schema storage;
create table storage.objects( id int primary key, owner uuid);

create policy storage_owner_check on storage.objects
for select
to authenticated
using (owner = auth.uid());

alter table storage.objects enable row level security;

-- 1 entry for storage.objects
select * from lint."0003_auth_rls_initplan";

rollback to savepoint a;

-- auth remains excluded: users do not author policies there
create table auth.sessions( id int primary key, user_id uuid);

create policy auth_sessions_check on auth.sessions
for select
to authenticated
using (user_id = auth.uid());

alter table auth.sessions enable row level security;

-- No issues
select * from lint."0003_auth_rls_initplan";

rollback;
Loading