examples
Supabase Security Examples
Examples are where concepts turn into action. Use these scenarios to recognize exposure patterns early — and to choose fixes that hold up under direct API access, not just in the UI.
What you’ll find in these Supabase security examples
- Concrete scenarios (how the exposure shipped)
- What went wrong (root cause, not symptoms)
- What fixed it (actionable changes)
- Why the fix works (so you can generalize it)
- Takeaways you can apply to your own schema
Browse Supabase security examples by topic
| Topic | Examples | URL |
|---|---|---|
| Admin Panel Client-Only Auth | 2 | /examples/admin-panel-client-auth-only |
| API Cache Leaks Private Data | 2 | /examples/api-cache-private-data-leak |
| Audit Log Table Publicly Readable | 2 | /examples/audit-log-public-readable |
| Auth Role Claim Confusion | 2 | /examples/auth-role-claim-confusion |
| Client Role Grants (anon/authenticated) | 2 | /examples/client-role-grants |
| Billing Webhook Idempotency Gap | 2 | /examples/billing-webhook-idempotency-gap |
| Broad DELETE for Authenticated Role | 2 | /examples/broad-authenticated-delete |
| Broad SELECT for Authenticated Role | 2 | /examples/broad-authenticated-select |
| Broad UPDATE for Authenticated Role | 2 | /examples/broad-authenticated-update |
| Broken Object Level Authorization (BOLA) | 2 | /examples/broken-object-level-authorization |
| Bucket LIST Permission Too Broad | 2 | /examples/bucket-list-permission-too-broad |
| Bulk Export Endpoint Overexposure | 2 | /examples/bulk-export-endpoint-overexposure |
| CORS Misconfiguration in Edge Functions | 2 | /examples/cors-misconfiguration-edge-functions |
| Cross-Schema Data Exposure | 2 | /examples/cross-schema-exposure |
| CSV Import Trusts Client Columns | 2 | /examples/csv-import-trusts-client-columns |
| Data API Custom Schema Misconfiguration | 2 | /examples/data-api-custom-schema-misconfiguration |
| Data API Public Schema Exposure | 2 | /examples/data-api-public-schema-exposure |
| Database URL Leaked in Client | 2 | /examples/leaked-database-url-in-client |
| Default Function EXECUTE to PUBLIC | 2 | /examples/default-function-execute-to-public |
| Default Privilege Drift | 2 | /examples/default-privilege-drift |
| Dependency Drift Misses Security Updates | 2 | /examples/dependency-drift-security-updates-missed |
| Edge Function JWT Verification Gap | 2 | /examples/edge-function-jwt-verification-gap |
| Edge Function Service Role Overuse | 2 | /examples/edge-function-service-role-overuse |
| Environment Parity Security Drift | 2 | /examples/env-parity-security-drift |
| Expired Signed URL Caching Leak | 2 | /examples/expired-signed-url-caching-leak |
Categorization filters (find the right example fast)
Use these filters to jump to the most relevant topic before you read individual examples:
- Surface: tables (RLS, grants), Storage (buckets, signed URLs), RPC (EXECUTE grants), secrets (service_role).
- Failure mode: public read, public write, enumeration/listing, bypass via RPC, leaked credentials.
- Goal: understand, reproduce, fix, verify, prevent drift.
Topic pages act like “filters”: they group examples under a security concept and link to templates and glossary definitions.
How to use examples during remediation
- Find the example that matches your finding (tables, storage, RPC).
- Compare your current state to the scenario description.
- Apply the fix pattern via a template or conversion guide.
- Verify by attempting direct client access (should fail).
- Re-scan to confirm the issue is gone.
How to reproduce an example safely (without guessing)
Reproduction is a superpower: if you can reproduce the issue once, you can prove the fix worked.
- Pick the closest example to your finding and identify the concrete resource (table/bucket/function).
- Attempt direct access using the same client credentials your app ships (anon/authenticated).
- Record the request and response (what succeeded, what failed, what status codes).
- Apply the template/conversion and repeat the same direct access test.
- Keep the reproduction steps as a regression guard for future migrations.
Common patterns across exposures
- RLS disabled or assumed (policies exist but don’t apply).
- Policies too broad (not bound to auth.uid() or tenant boundaries).
- Storage buckets left public or listable.
- RPC functions callable because EXECUTE grants weren’t revoked.
- Secrets accidentally leaking into the client bundle or logs.
Example index (selected)
- Admin Panel Client-Only Auth: direct API bypass →
/examples/admin-panel-client-auth-only/direct-api-bypass-admin-panel-client-auth-only— A real-world pattern where Admin Panel Client-Only Auth is exploited through direct API calls that bypass frontend assumptions and expose sensitive operations. - Admin Panel Client-Only Auth: migration drift regression →
/examples/admin-panel-client-auth-only/migration-drift-admin-panel-client-auth-only— A migration introduces drift that reopens Admin Panel Client-Only Auth despite earlier hardening, creating a realistic regression path in production. - API Cache Leaks Private Data: direct API bypass →
/examples/api-cache-private-data-leak/direct-api-bypass-api-cache-private-data-leak— A real-world pattern where API Cache Leaks Private Data is exploited through direct API calls that bypass frontend assumptions and expose sensitive operations. - API Cache Leaks Private Data: migration drift regression →
/examples/api-cache-private-data-leak/migration-drift-api-cache-private-data-leak— A migration introduces drift that reopens API Cache Leaks Private Data despite earlier hardening, creating a realistic regression path in production. - Audit Log Table Publicly Readable: direct API bypass →
/examples/audit-log-public-readable/direct-api-bypass-audit-log-public-readable— A real-world pattern where Audit Log Table Publicly Readable is exploited through direct API calls that bypass frontend assumptions and expose sensitive operations. - Audit Log Table Publicly Readable: migration drift regression →
/examples/audit-log-public-readable/migration-drift-audit-log-public-readable— A migration introduces drift that reopens Audit Log Table Publicly Readable despite earlier hardening, creating a realistic regression path in production. - Auth Role Claim Confusion: direct API bypass →
/examples/auth-role-claim-confusion/direct-api-bypass-auth-role-claim-confusion— A real-world pattern where Auth Role Claim Confusion is exploited through direct API calls that bypass frontend assumptions and expose sensitive operations. - Auth Role Claim Confusion: migration drift regression →
/examples/auth-role-claim-confusion/migration-drift-auth-role-claim-confusion— A migration introduces drift that reopens Auth Role Claim Confusion despite earlier hardening, creating a realistic regression path in production. - Authenticated SELECT on a sensitive table →
/examples/client-role-grants/authenticated-select-on-sensitive-table— Authenticated SELECT turned a sensitive table into an open endpoint. - Billing Webhook Idempotency Gap: direct API bypass →
/examples/billing-webhook-idempotency-gap/direct-api-bypass-billing-webhook-idempotency-gap— A real-world pattern where Billing Webhook Idempotency Gap is exploited through direct API calls that bypass frontend assumptions and expose sensitive operations. - Billing Webhook Idempotency Gap: migration drift regression →
/examples/billing-webhook-idempotency-gap/migration-drift-billing-webhook-idempotency-gap— A migration introduces drift that reopens Billing Webhook Idempotency Gap despite earlier hardening, creating a realistic regression path in production. - Broad DELETE for Authenticated Role: direct API bypass →
/examples/broad-authenticated-delete/direct-api-bypass-broad-authenticated-delete— Authenticated DELETE allowed attackers to remove other users’ rows.
How to generalize from one example to your whole schema
Each example is a pattern. Once you understand the pattern, you can apply it across tables, buckets, and functions.
- If a fix is “backend-only access,” apply it consistently across all sensitive resources, not just one table.
- If a fix is “private buckets + signed URLs,” standardize naming and TTL rules across every download flow.
- If a fix is “revoke public EXECUTE,” inventory functions and make function review part of migrations.
That’s how you get durable security improvements instead of one-off patches.
Supabase security example workflow (short version)
If you want the fastest path from reading to reducing risk, follow this loop:
- Pick a topic that matches your surface (tables/Storage/RPC/secrets).
- Read one example and reproduce the issue once via direct access (so you can verify the fix later).
- Apply a template/conversion and repeat the same direct access test (it must fail).
- Add a drift guard after migrations so the pattern doesn’t reappear.
How to extract a reusable pattern from one example
Examples are most valuable when you convert them into a checklist you can reuse across your whole app.
- Name the surface (table / Storage bucket / RPC function / secret) and write it down as the resource under test.
- Write a one-sentence boundary statement (for example: “only the backend can download invoices”).
- Write the one direct access test that would violate that statement if the boundary is missing.
- Apply the fix pattern and repeat the same test until it fails reliably.
- Add the test to your release checklist so you catch drift after migrations.
This turns a story into a repeatable control.
If you can’t find an example that matches your case
Use examples as patterns, not as exact replicas of your schema.
- Match by surface: tables vs Storage vs RPC vs secrets.
- Match by failure mode: public read, public write, enumeration/listing, parameter tampering, leaked key.
- If none are close, start with
/glossaryto name the concept, then use/templatesor/integrationsto implement the fix pattern.
Once you have one verified fix, you can generalize it across similar resources.
FAQ
Are these examples based on real incidents?
They’re written to mirror the most common real-world exposure patterns in Supabase apps. Always validate in your own project before applying a fix.
Should I copy the exact fix from an example?
Use the example to understand the pattern, then apply the matching template/conversion to your own table, bucket, or function with verification steps.
What’s the fastest verification method?
Attempt direct access using the same client credentials your app ships. If it fails and backend endpoints still work, the fix is effective.
Next step
Want examples tied to your exact findings? Run a Mockly scan and follow the linked examples and templates from each issue.