Remove anon default table privileges on production #470
Copy link
Copy link
Closed
Labels
SecuritySecurity, access control, and data exposureSecurity, access control, and data exposure
Milestone
Description
Summary
Production never ran 29-lint-hardening.sql §3, so anon still holds default table privileges on production tables outside the 2026-09-28 hand fix. #316 covers only objects created in the future.
- Exposure: RLS still applies to every table that has it on, so anon reads stay limited by policy. The gap is any table without RLS, and any future table that ships without its own revoke.
- Source: the Port the 2026-09-28 prod grant and RLS fix into scripts and a paired migration #314 review, 2026-10-08 (
packages/supabase/CLAUDE.md, the "Production never ran" bullet).
Fix
- Read-only on prod: list every table in
publicwhereanonhas INSERT, UPDATE, DELETE or TRUNCATE, and every table withrelrowsecurity = false. - Write one migration that revokes anon writes everywhere except where a policy needs them. Keep the anon SELECT allowlist from §6 and §7.
- Mirror it in the scripts, and regenerate
seed.sql.
Acceptance
- The read-only listing is posted here before and after.
- No anon write privilege remains on a table without a policy that needs it.
Metadata
Metadata
Assignees
Labels
SecuritySecurity, access control, and data exposureSecurity, access control, and data exposure
Activity
HMarzban commentedon Oct 15, 2026
Related issues
db push#317 — Related: Add a read-only grant guard to run after eachdb push#317 listsanon_writeandanon_read_not_allowedon prod with no owner. This issue owns them. The Add a read-only grant guard to run after eachdb push#317 guard can prove the fix before and after.Cross-link review, 2026-10-15. Generated by Claude Code
fix(supabase): harden grants and notification gates
HMarzban commentedon Oct 19, 2026
Prod check after the 2026-10-19
db push(read-only)Migration
20261014121200_revoke_anon_default_table_privilegesis applied on prod.After:
check-grants.sqlshows noanon_writerow and noanon_read_not_allowedrow. Anon reads only the allowlisted tables, and it writes to no table inpublic.Before: no listing was posted here before the push, and it cannot be taken now. The earlier prod state is in the 2026-09-28 review on #327.
What remains: the default privileges for new objects (
pg_default_acl) still grant anon onpublic. That is #316, by design, andcheck-grants.sqlexpects thosedefault_acl_anonrows until #316 lands.