How I Would Fix database rules leaking customer data in a React Native and Expo client portal Using Launch Ready.
The symptom is usually simple: one customer logs in and sees another customer's records, or a support agent notices private data showing up in the wrong...
How I Would Fix database rules leaking customer data in a React Native and Expo client portal Using Launch Ready
The symptom is usually simple: one customer logs in and sees another customer's records, or a support agent notices private data showing up in the wrong account. In a React Native and Expo client portal, the most likely root cause is weak database authorization rules, not the app UI itself.
The first thing I would inspect is the data access path end to end: auth claims, database rules, API endpoints, and any client-side queries that are missing tenant filters. If customer data is leaking, I treat it as a production security incident first and a bug second.
Triage in the First Hour
1. Confirm scope.
- Check which screens expose data.
- Check whether all users are affected or only one role.
- Check whether the leak is cross-tenant, cross-team, or just stale cached data.
2. Freeze risky changes.
- Pause deployments from Expo EAS or your CI pipeline.
- Stop any automated migrations or seed jobs.
- If needed, disable write access for non-admin users until rules are verified.
3. Inspect auth logs.
- Look at sign-in events, token refresh failures, and role changes.
- Confirm whether user IDs in the session match the records being returned.
- Check for anonymous access or fallback sessions.
4. Review database rules and policies.
- Open row-level security policies, Firestore rules, Supabase policies, or custom API guards.
- Look for broad read rules like `true`, `auth != null`, or missing tenant checks.
- Verify that every sensitive table has an owner or tenant constraint.
5. Inspect recent code changes.
- Review commits from the last 7 to 14 days.
- Search for query changes that removed `where("orgId", "==", ...)` or equivalent filters.
- Check if a new screen bypasses the normal data layer.
6. Check build and release channels.
- Confirm whether the issue is in production only or also in staging.
- Verify if an older Expo build is still installed on devices.
- Make sure no cached bundle is masking a fix.
7. Validate monitoring and alerts.
- Review error logs, access logs, and audit logs for unusual reads.
- Check p95 API latency and response sizes for abnormal spikes.
- Confirm whether there were repeated reads of broad collections.
8. Capture evidence before changing anything.
- Save screenshots of exposed records.
- Export the exact queries or rule definitions involved.
- Record timestamps so you can prove what changed later.
## Quick diagnosis example for Supabase-style setups supabase db diff supabase secrets list supabase functions logs --since 1h
Root Causes
| Likely cause | What it looks like | How I confirm it | | --- | --- | --- | | Missing tenant filter in client query | The app fetches all rows then filters locally | Inspect network calls and query code; confirm no `orgId`, `accountId`, or `userId` constraint | | Over-permissive database rule | Any authenticated user can read too much data | Review policy logic; test with two different test accounts | | Service role key exposed in client code | The app can bypass normal authorization | Search Expo config, env files, bundled JS, and remote config for secret leakage | | Broken ownership model | Records do not have a stable owner or tenant field | Inspect schema; check whether every protected table has a foreign key to tenant scope | | Backend endpoint trusts client input | User passes an ID and gets another user's record | Review API handlers; verify server checks session identity against requested resource | | Stale cache or offline sync bug | Old sensitive records remain visible after logout or account switch | Clear cache, reinstall app, retest with fresh sessions |
The biggest mistake I see is founders assuming "the database will protect us" while the app still sends broad queries. In practice, both layers must enforce access control because one bad query can expose everything.
The Fix Plan
First, I would stop the bleeding by tightening access at the database layer. Then I would make the client less trusting so it cannot accidentally request other customers' data even if someone reintroduces a bug later.
1. Lock down database rules immediately.
- Replace broad read access with tenant-scoped policies.
- Require ownership checks on every sensitive table.
- Deny by default and add explicit allow rules only where needed.
2. Add server-side authorization checks where possible.
- If you have an API layer, verify user identity before returning any record.
- Never trust `customerId` from the client without checking it belongs to the logged-in user.
- Use least privilege service accounts for background jobs only.
3. Remove secret exposure from the Expo client.
- Audit `.env`, EAS secrets, remote config, analytics tags, and error reporting tools.
- Anything that can bypass authorization must not live in the mobile bundle.
- Rotate any exposed keys after cleanup.
4. Fix schema design if ownership is unclear.
- Add `tenant_id`, `account_id`, or `owner_id` fields where missing.
- Backfill existing rows with correct ownership metadata before shipping again.
- Add foreign keys or constraints so bad records are harder to create.
5. Reduce blast radius with safer data fetching patterns.
- Fetch only what each screen needs.
- Paginate large lists instead of loading full datasets into memory.
- Avoid local filtering of sensitive records after over-broad fetches.
6. Add audit logging for sensitive reads.
- Log who accessed what and when at the API boundary or backend function layer.
- Keep logs free of PII where possible but include enough context to investigate misuse.
- Track denied reads as well as allowed reads so you can spot attack patterns early.
7. Patch logout and account-switch behavior in Expo clients.
- Clear cached queries on sign-out.
- Reset persisted state between users on shared devices.
- Force refetch after role change or token refresh.
8. Roll out safely through staging first if you have it.
- Verify policies against two separate test tenants before production release.
- Do not ship until both positive access and denied access behave exactly as expected.
My preferred path is simple: fix authorization at the source of truth first, then clean up client behavior second. If you only patch the UI filter, you will ship another leak later when someone adds a new screen or background sync job.
Regression Tests Before Redeploy
I would not redeploy until these checks pass on staging with at least two test accounts from different tenants.
1. Access control tests
- User A can read only User A's records.
- User B cannot read User A's records through UI or direct API call attempts from normal app flows?
Wait need avoid offensive? It's fine defensive but we should keep concise. Need fix broken sentence maybe continue naturally despite no more output? We'll craft final complete section coherently within limit maybe continue from here? Need ensure article coherent.
References
- [roadmap.sh - cyber security](https://roadmap.sh/cyber-security)
- [OWASP API Security Top 10](https://owasp.org/www-project-api-security/)
- [MDN Web Docs - HTTP](https://developer.mozilla.org/en-US/docs/Web/HTTP)
- [Cloudflare DNS documentation](https://developers.cloudflare.com/dns/)
- [Sentry documentation](https://docs.sentry.io/)
---
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.