How I Would Fix database rules leaking customer data in a Supabase and Edge Functions mobile app Using Launch Ready.
If customer records are showing up in the wrong mobile account, I treat it as a production security incident first and a bug second. The most likely root...
How I Would Fix database rules leaking customer data in a Supabase and Edge Functions mobile app Using Launch Ready
If customer records are showing up in the wrong mobile account, I treat it as a production security incident first and a bug second. The most likely root cause is broken Row Level Security, an Edge Function using the service role key too broadly, or a query path that bypasses the intended auth checks.
The first thing I would inspect is the exact path from mobile app to Supabase table: which screen loads the data, which Edge Function calls it, and whether that request is using the anon key, user JWT, or service role. In practice, leaks usually happen because one layer assumes another layer already filtered access.
If the app is already built but unsafe to ship, I would use this sprint to stabilize the launch surface while I repair the data exposure.
Triage in the First Hour
1. Confirm the leak with one test account and one unrelated account.
- Open two separate mobile logins.
- Check whether user A can see user B's rows, messages, files, or profile data.
- Note exactly which screen and action exposes the data.
2. Inspect Supabase auth and RLS status.
- Check whether affected tables have RLS enabled.
- Review policies for `select`, `insert`, `update`, and `delete`.
- Confirm whether any policy uses overly broad conditions like `true` or missing ownership checks.
3. Review Edge Function logs.
- Look for functions reading from tables with the service role key.
- Check whether user identity is passed into the function and verified before querying data.
- Look for logs that reveal full payloads or private fields.
4. Review recent deploys.
- Check what changed in the last 1 to 3 releases.
- Look at schema migrations, policy changes, function updates, and client SDK changes.
- Identify any hotfixes that may have disabled auth checks.
5. Audit secrets and environment variables.
- Confirm service role keys are not exposed in the mobile client.
- Verify production and staging env vars are not mixed.
- Check Cloudflare or hosting config for accidental public exposure of private endpoints.
6. Inspect client-side query paths.
- Search for direct table reads from screens that should go through an authenticated function.
- Check for cached responses being shared across users on device or CDN layers.
- Verify user-specific queries include stable filters like `user_id = auth.uid()`.
7. Freeze risky changes until containment is clear.
- Pause new deploys if customer data exposure is active.
- Disable any nonessential admin endpoints.
- Notify support so they can handle reports consistently.
-- Quick containment check select schemaname, tablename, rowsecurity from pg_tables where schemaname = 'public'; -- Example policy review select * from pg_policies where schemaname = 'public' order by tablename;
Root Causes
1. RLS is off on one or more tables.
- How to confirm: query `pg_tables.rowsecurity` and compare against every customer-facing table.
- Common symptom: authenticated users can read all rows through direct Supabase queries.
2. Policies are too broad or written on the wrong column.
- How to confirm: inspect policy SQL for missing ownership checks or conditions based on mutable fields like email instead of immutable user IDs.
- Common symptom: users see records that match a loose filter but do not belong to them.
3. Edge Functions use the service role key without re-checking identity.
- How to confirm: search function code for service role usage and verify it validates `Authorization` headers before any database call.
- Common symptom: one privileged endpoint returns cross-account data because it trusts a client-supplied identifier.
4. The mobile client queries tables directly when it should call a protected function.
- How to confirm: inspect network traffic and code paths in React Native or Flutter for direct Supabase table access from sensitive screens.
- Common symptom: data appears correct in one flow but leaks in another because one path bypasses server-side logic.
5. Cached responses are shared across users.
- How to confirm: review Cloudflare caching rules, app-level caches, and any function response headers like `Cache-Control`.
- Common symptom: one user's dashboard briefly shows another user's content after login switch or session refresh.
6. Legacy test data or seed data was promoted into production-like environments.
- How to confirm: compare record ownership fields across staging and production databases and inspect migration scripts for copied customer rows.
- Common symptom: support reports "random" records appearing because stale demo content was never isolated.
The Fix Plan
My goal is to stop leakage first, then repair access control without breaking legitimate users. I would not try to "patch around" bad policies with frontend filters only, because that gives you a false sense of safety while the database still leaks.
1. Contain exposure immediately.
- Disable public access paths that return sensitive rows without auth checks.
- Rotate any exposed secrets if there is even a chance they were committed or logged.
- If needed, temporarily gate high-risk screens behind maintenance messaging while keeping core login functional.
2. Make ownership explicit at the database level.
- Ensure every customer-owned table has RLS enabled.
- Use immutable identifiers such as `auth.uid()` tied to a `user_id` column where possible.
- Avoid relying on email addresses as ownership keys unless there is no better option and you understand verification timing risks.
3. Rewrite policies to be least privilege only.
- Separate read policies from write policies.
- Give each table only the minimum operations needed by each role.
- Remove any policy that allows unrestricted selects during testing unless it is strictly limited to admin roles in a protected schema.
4. Lock down Edge Functions by default.
- Treat service role access as privileged backend-only access.
- Validate JWTs inside every function before reading private data.
- Reject requests missing authentication rather than trying to infer identity from query parameters alone.
5. Reduce blast radius in function design.
- Split admin tasks from customer-facing reads into different functions if they serve different trust levels.
- Pass only necessary fields into logs and response bodies.
- Return normalized error messages so private schema details do not leak through stack traces.
6. Fix caching headers and CDN behavior where needed.
- Set private responses to non-cacheable unless you have proven safe per-user caching behavior.
```http Cache-Control: no-store ```
This matters if Cloudflare sits in front of your app or function routes. Shared caches can turn one user's response into another user's problem very quickly.
7. Add an emergency rollback path before redeploying again.
- Keep one known-good release tag ready to restore if validation fails after deployment.
* Use feature flags if you need partial rollout instead of full release reversal.*
8. Verify production secrets and environment separation during Launch Ready setup if needed now: * DNS points only where intended.* * SSL is valid.* * Redirects are correct.* * Subdomains are isolated.* * Environment variables are split cleanly between staging and prod.* * Monitoring alerts fire within minutes if errors spike.*
Regression Tests Before Redeploy
I would not ship this fix until I can prove isolation under realistic user flows. For a mobile app with Supabase and Edge Functions, I want both automated checks and manual spot tests because security bugs often hide in edge cases that unit tests miss.
Acceptance criteria:
- User A cannot read User B's rows through direct table access or via any Edge Function route.
- Anonymous requests fail closed on protected endpoints with no private payload returned.
- Service role usage does not bypass ownership checks for customer-facing reads.
- Cached responses do not persist across user sessions on device or at CDN level.
Test checklist: 1. Login isolation test
- Create two test accounts with distinct customer records
- Log out fully between sessions
- Confirm no cross-account records appear after switching accounts
2. Direct query test
- Attempt reads against sensitive tables using anon credentials
- Confirm RLS blocks unauthorized access with expected errors
3. Function authorization test
- Call each protected Edge Function with:
1) no token, 2) invalid token, 3) valid token from another user, 4) valid token from owning user
- Confirm only case 4 succeeds
4. Cache behavior test
- Open the same screen on two accounts over shared Wi-Fi
- Hard refresh app state where possible
- Confirm no response reuse between accounts
5. Negative test coverage target
- At least 10 security-focused cases covering unauthorized select/update/delete attempts
- At least 90 percent coverage on critical auth helpers and policy-related business logic
6. Manual exploratory pass
- Switch accounts quickly on one device
- Kill and relaunch app mid-session
- Test expired tokens, offline mode, empty states, and retry flows
7. Observability check
- Confirm logs show request IDs without sensitive payloads
- Confirm alerts fire on repeated authorization failures or unusual row counts returned per request
Prevention
I would put guardrails around this so one rushed change does not reopen the leak next month.
| Area | Guardrail | Why it matters | |---|---|---| | Database | RLS required on all customer tables | Prevents accidental public reads | | Code review | Security checklist before merge | Catches bad policies before deploy | | Edge Functions | Auth check at entry point | Stops privileged functions from trusting clients | | Logging | No private payloads in logs | Reduces secondary data exposure | | Monitoring | Alerts on unusual row counts | Surfaces cross-account reads fast | | QA | Cross-account regression suite | Prevents recurrence after refactors |
I would also add these controls:
- Review every migration for policy impact before merge approval by at least one senior engineer or founder-level reviewer who understands risk trade-offs enough to ask questions about access control rather than just UI polish?
- Store secrets only in approved environment managers with rotation documented?
- Add rate limits on public endpoints so brute-force probing does not turn into support load?
- Keep mobile UX clear about loading states so users do not spam retry buttons during slow auth refreshes?
- Watch p95 latency on protected functions; once it climbs above about 500 ms consistently, teams start adding unsafe shortcuts just to make screens feel faster?
From an AI red-teaming lens, if any part of your app uses AI prompts alongside customer records, I would also test prompt injection and tool misuse separately so model output cannot reveal hidden rows through indirect instructions? That belongs in the same security backlog because leaked context can become leaked data just as fast as a bad SQL policy can?
When to Use Launch Ready
Use Launch Ready when you need production basics fixed fast around this security issue instead of spreading work across random freelancers or half-finished tickets? It fits best when your product already works but deployment hygiene is weak: domains misconfigured, SSL inconsistent, env vars messy, monitoring missing, or launches blocked by infrastructure uncertainty?
- Domain setup
- Email setup with SPF/DKIM/DMARC
- Cloudflare configuration
- SSL setup
- Redirects and subdomains
- Production deployment support
- Secrets and environment variable cleanup
- Caching and DDoS protection basics
- Uptime monitoring
- Handover checklist
What you should prepare: 1. Supabase project access with admin permissions? 2. Edge Functions repository access? 3. Mobile build pipeline access? 4. Current production URL list? 5. A short list of screens where sensitive data appears? 6. Any recent incident examples from support?
Then I hand back a tighter system with fewer ways to leak customer data accidentally?
Delivery Map
References
1. Roadmap.sh Cyber Security Best Practices https://roadmap.sh/cyber-security
2. Roadmap.sh API Security Best Practices https://roadmap.sh/api-security-best-practices
3. Roadmap.sh QA https://roadmap.sh/qa
4. Supabase Row Level Security docs https://supabase.com/docs/guides/database/postgres/row-level-security
5. Supabase Edge Functions docs https://supabase.com/docs/guides/functions
---
Take the next step
If this is a problem in your product right now, here is what to do next:
- [Use the free Cyprian tools](/tools) - estimate cost, score app risk, check launch readiness, or pick the right service sprint.
- [Book a discovery call](/contact) - I will tell you honestly whether you need a sprint or if you can DIY the next step.
*Written by Cyprian Tinashe Aarons - senior full-stack and AI engineer helping founders rescue, launch, automate, and scale AI-built products.*
Cyprian Tinashe Aarons — Senior Full Stack & AI Engineer
Cyprian helps founders rescue, secure, deploy, and automate AI-built apps with production-grade engineering, launch systems, and AI integration.