Replies: 5 comments
|
You will not be able to change storage but by default there is no access from the REST API to them. It appears default is supabase removes SELECT/UPDATE/INSERT/DELETE as the REST API could use those. There recent lockdown of grants for for the REST API. You can't truncate from the API directly. So unless your write a trigger function to do truncate or you use those roles thru the DB interface on your own Truncate can't be used. related: Besides revoking, not clear you can set a default, but I've not done much research on it. |
|
Adding the parts that are still open, from having run this exact audit on a production project. 1. Yes, these are managed defaults, not something your migrations did. You can see exactly who set them: select pg_get_userbyid(defaclrole) as granted_by,
defaclnamespace::regnamespace as schema,
defaclobjtype,
defaclacl
from pg_default_acl;The rows whose 2. To stop future tables from receiving them, run this as alter default privileges for role postgres in schema public
revoke truncate, trigger on tables from anon, authenticated;Then query 3. Existing tables — your transactional test was right, and it is safe: revoke truncate, trigger on all tables in schema public from anon, authenticated;
4. Can select has_table_privilege('anon', 'public.your_table', 'TRUNCATE');5. Where I would spend the rest of a least-privilege audit. TRUNCATE and TRIGGER on
Both of those are reachable by anyone holding your anon key, which TRUNCATE is not — so if you are prioritising before rollout, I would do those two first and treat the TRUNCATE/TRIGGER cleanup as hygiene. The read-only version of these checks, if it saves you writing them: https://github.com/basildraz-arch/supabase-rls-audit |
|
Sizin gözlemlediğiniz Kısaca: Soru 2 — anon/authenticated bunları kullanabilir mi? Çoğu durumda hayır, iki katman engeller: (1) Soru 3 & 4 — desteklenen revoke yolu: DO $$
DECLARE r record;
BEGIN
FOR r IN
SELECT schemaname, tablename
FROM pg_tables
WHERE schemaname IN ('storage')
LOOP
EXECUTE format('REVOKE TRUNCATE, TRIGGER ON %I.%I FROM anon, authenticated', r.schemaname, r.tablename);
END LOOP;
END
$$;Mevcut tablolarda bu çalışır. Gelecekteki tablolar için ise storage damarının bu default ACL'leri Soru 5 — Storage'ı kırar mı? Kırmaz. Storage API asla anon/authenticated rolüyle -- UPLOAD: çalışıyor mu?
mkdir('revoke-test-'+now()::text)İsterseniz DO bloğunu başka bir migration'a ekleyip |
|
This is Postgres default grants — new Supabase projects grant Verify: SELECT * FROM pg_default_acl WHERE defaclobjtype = 'r' AND defaclnamespace = 'storage'::regnamespace;Fix (revoke unwanted defaults): ALTER DEFAULT PRIVILEGES IN SCHEMA storage REVOKE TRUNCATE, TRIGGER ON TABLES FROM PUBLIC;
ALTER DEFAULT PRIVILEGES IN SCHEMA storage REVOKE TRUNCATE, TRIGGER ON TABLES FROM anon;
ALTER DEFAULT PRIVILEGES IN SCHEMA storage REVOKE TRUNCATE, TRIGGER ON TABLES FROM authenticated;
-- Then re-grant only what you need:
ALTER DEFAULT PRIVILEGES IN SCHEMA storage GRANT SELECT ON TABLES TO anon;
ALTER DEFAULT PRIVILEGES IN SCHEMA storage GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO authenticated;Note: This affects future tables. For existing tables, revoke explicitly: REVOKE TRUNCATE, TRIGGER ON storage.objects FROM PUBLIC, anon, authenticated;Free audit script: https://github.com/cekuu35/supabase-rls-leak-demo |
|
Three corrections on the answer above, because this is a hardening pass before production and one of those steps can take Storage down. 1. Check the grantee before you write the revoke. The opening post says the grants sit on select grantee, privilege_type
from information_schema.role_table_grants
where table_schema = 'storage'
and table_name in ('objects','buckets','buckets_analytics')
and privilege_type in ('TRUNCATE','TRIGGER')
order by grantee, privilege_type;2. Default privileges are recorded per (owner role, schema). With no select pg_get_userbyid(defaclrole) as owner,
defaclnamespace::regnamespace as schema,
defaclacl
from pg_default_acl
where defaclnamespace = 'storage'::regnamespace;3. This is the one that matters: do not widen the revoke on
which reads like a policy problem and is not one. It is one of the more common causes of that error, and it is painful to diagnose precisely because the policies are correct. The loop in the answer above revokes For the same reason I would leave the future-tables default alone in alter default privileges in schema storage
grant select, insert, update, delete on tables to authenticated;That is a standing rule that every table Supabase adds to On the original question, the short version: TRUNCATE and TRIGGER on |
Uh oh!
There was an error while loading. Please reload this page.
We created a new Supabase project and applied our migration set successfully.
During a least-privilege audit, we found that anon and authenticated have TRUNCATE and TRIGGER privileges on 39 tables:
36 tables in public
3 tables in storage
Total: 156 grants.
We traced the default ACL sources to:
supabase_admin → public
postgres → public/storage
Attempting to modify the managed defaults from the available postgres connection fails with:
42501 — permission denied to change default privileges
A transactional test showed that explicit:
REVOKE TRUNCATE, TRIGGER
succeeds for the 36 public tables, but the grants remain on:
storage.buckets
storage.objects
storage.buckets_analytics
We rolled the test back and have not modified production privileges.
RLS remains enabled and policies are correct, but we want to enforce strict least privilege before production rollout.
Could someone clarify:
Are these TRUNCATE / TRIGGER grants expected managed defaults?
Can anon or authenticated actually exercise them despite RLS?
What is the supported way to revoke them from existing public and storage tables?
What is the supported way to change the managed default privileges so future tables do not receive them?
Would removing these grants interfere with Supabase Storage or other managed services?
All reactions